package etxt2db.annotators;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.text.ParseException;
import java.util.Iterator;
import java.util.List;

import com.aliasi.chunk.Chunk;
import com.aliasi.chunk.Chunking;
import com.aliasi.dict.DictionaryEntry;
import com.aliasi.dict.ExactDictionaryChunker;
import com.aliasi.dict.MapDictionary;
import com.aliasi.tokenizer.IndoEuropeanTokenizerFactory;

import edu.cmu.minorthird.text.BasicTextLabels;
import edu.cmu.minorthird.text.MonotonicTextLabels;
import edu.cmu.minorthird.text.Span;
import edu.cmu.minorthird.text.TextBaseLoader;
import edu.cmu.minorthird.text.TextLabels;
import etxt2db.api.ClassificationModel;
import etxt2db.corpus.CompleteTextLabels;
import etxt2db.corpus.NoTokenSpan;


public class DictionaryClassificationModel extends ClassificationModel implements Serializable {
	private static final long serialVersionUID = -782912453005188658L;
	private MapDictionary<String> dictionary;
	private boolean caseSensitive;
	ExactDictionaryChunker dictionaryChunkerFT; 
	
	public DictionaryClassificationModel(File dictionaryFile) throws IOException, ParseException {
		this(dictionaryFile, true);
    }
	
	public DictionaryClassificationModel(File dictionaryFile, boolean caseSensitive) throws IOException, ParseException {
		this.caseSensitive=caseSensitive;
		TextBaseLoader baseLoader = new TextBaseLoader();
		baseLoader.load(dictionaryFile);
		TextLabels labels = baseLoader.getLabels();
		
		dictionary = new MapDictionary<String>();
		
		for(String attribute : labels.getTypes()){
			for(Span text : labels.getTypeSet(attribute, dictionaryFile.getName())){
				if(caseSensitive){
					dictionary.addEntry(new DictionaryEntry<String>(text.asString(),attribute,0));
				}else{
					dictionary.addEntry(new DictionaryEntry<String>(text.asString().toLowerCase(),attribute,0));
				}
			}
		}
		dictionaryChunkerFT = new ExactDictionaryChunker(dictionary, IndoEuropeanTokenizerFactory.FACTORY,false,true); 
    }
	
	public DictionaryClassificationModel(List<String> dic, String type, boolean caseSensitive) {
		this.caseSensitive=caseSensitive;
		dictionary = new MapDictionary<String>();
		
		for(String entry : dic){
			if(caseSensitive){
				dictionary.addEntry(new DictionaryEntry<String>(entry,type,0));
			}else{
				dictionary.addEntry(new DictionaryEntry<String>(entry.toLowerCase(),type,0));
			}
		}
		dictionaryChunkerFT = new ExactDictionaryChunker(dictionary, IndoEuropeanTokenizerFactory.FACTORY,false,true); 
    }
	
	@SuppressWarnings("deprecation")
	@Override
	public void annotate(MonotonicTextLabels arg0) {
		System.out.println("Starting now!");
		long time = System.currentTimeMillis();
		Iterator<Span> iter = arg0.getTextBase().documentSpanIterator();
		while(iter.hasNext()){
			Span span = iter.next();
			//The chunking interface of Lingpipe uses strings, so we need to
			//convert our documents to strings.
			Chunking chunking;
			if(caseSensitive){
				chunking = dictionaryChunkerFT.chunk(span.asString());
			}else{
				chunking = dictionaryChunkerFT.chunk(span.asString().toLowerCase());
			}
			for (Chunk chunk : chunking.chunkSet()) {
				//Each chunk gives us the start and end of the span we want to
				//annotate
	            int start = chunk.start();
	            int end = chunk.end();
	            
	            //Luckily it is what we want in the Span interface
	            NoTokenSpan newSpan=new NoTokenSpan(span,span.getLoChar()+start,span.getLoChar()+end);
	            
	            //We add a new Span to the TexLabels
				((CompleteTextLabels)arg0).addNoTokenToType(newSpan,chunk.type());
	        }
		}
		System.out.println((System.currentTimeMillis()-time) + " miliseconds passed");
	}

	@Override
	public TextLabels annotatedCopy(TextLabels arg0) {
		//Just create a new TextLabels (copy) before annotate
		CompleteTextLabels copy = new CompleteTextLabels(arg0.getTextBase());
		annotate(copy);
		//Return the new TextLabels
		return copy;
	}

	@Override
	public String explainAnnotation(TextLabels arg0, Span arg1) {
		return "";
	}
}
